
#include "CanCardPCan.h"

#include <windows.h>

#include <iostream>
#include <string>
using namespace std;

#define CAN_INT -1
#define CAN_PORT -1


CanCardPCan::CanCardPCan(int Carte, int Bus, bool VerboseLog, int frequency, bool isUsb) :
	IsGood(false),
	m_i_DLL(NULL),
	m_CAN_Init(NULL),
	m_CAN_Close(NULL),
	m_CAN_Status(NULL),
	m_CAN_Write(NULL),
	m_CAN_Read(NULL),
	m_CAN_VersionInfo(NULL)
{
	std::string libFileName = "PCAN_PCI.DLL";

	if(isUsb)
		libFileName = "PCAN_USB.DLL";
	
	cout << "Initializing PCAN card..." << endl;
	if (!LoadDLL(libFileName.c_str()))
	{
		cout << "PCAN ERROR : error loading PCAN DLL" << endl;
		return;
	}
	cout << "PCAN INFO :DLL loaded" << endl;


	//-- open CAN Port ------------------------------------------------------------
	
	if (m_CAN_Init==NULL) // check if function pointer is vallid
		return;

	// init PCAN-USB
	int valFreq = CAN_BAUD_500K;
	switch(frequency)
	{
	case 5000:
		valFreq = CAN_BAUD_5K;
		break;
	case 10000:
		valFreq = CAN_BAUD_10K;
		break;
	case 20000:
		valFreq = CAN_BAUD_20K;
		break;
	case 50000:
		valFreq = CAN_BAUD_50K;
		break;
	case 100000:
		valFreq = CAN_BAUD_100K;
		break;
	case 125000:
		valFreq = CAN_BAUD_125K;
		break;
	case 250000:
		valFreq = CAN_BAUD_250K;
		break;
	case 500000:
		valFreq = CAN_BAUD_500K;
		break;
	case 1000000:
		valFreq = CAN_BAUD_1M;
		break;
	}
	DWORD ret = m_CAN_Init(valFreq, CAN_INIT_TYPE_ST);
		
	char ErrMessage[255];
	check_can_err(ret, ErrMessage);			// check can error message
	cout << "PCAN ERROR : CAN_Init " << ErrMessage << endl;		// display can error message
	if (ret!=CAN_ERR_OK)
		return;
	char DriverVersion[255];
	ret = m_CAN_VersionInfo(DriverVersion);

	if (ret==CAN_ERR_OK)
	{
		cout << "PCAN Driver Information:"<< endl;
		cout << DriverVersion << endl;	// display driver information on screen 
	}
	else
	{
		check_can_err(ret, ErrMessage);							// display error message if error occured
		cout << "PCAN_VersionInfo " << ErrMessage << endl;
		return;
	}

	IsGood = true;
}

bool CanCardPCan::good()
{
	return IsGood;
}

CanCardPCan::~CanCardPCan()
{
	if (m_CAN_Close!=NULL)
	{
		DWORD ret = m_CAN_Close();
		char ErrMessage[256];
		check_can_err(ret, ErrMessage);
		cout << "CAN_Close " << ErrMessage << endl;
	}
	UnloadDLL();
}

bool CanCardPCan::SendMsg(unsigned int ID, unsigned short DataLen, unsigned char* Data)
{
	TPCANMsg Msg;
	memset(&Msg, 0, sizeof(Msg));
	Msg.ID = ID;
	Msg.MSGTYPE = 0;
	Msg.LEN = (BYTE)DataLen;
	if (Data!=NULL && DataLen>0)
		memcpy(Msg.DATA, Data, DataLen);
	return sendMB(&Msg);
}

bool CanCardPCan::RcvMsg(unsigned int& ID, unsigned short& DataLen, unsigned char* Data)
{
	if (m_CAN_Read==NULL)
		return false;

	TPCANMsg Msg;
	memset(&Msg, 0, sizeof(Msg));
	DWORD ret = m_CAN_Read(&Msg);
	ID = Msg.ID;
	DataLen = Msg.LEN;
	memcpy(Data, Msg.DATA, DataLen);
	return ret==CAN_ERR_OK;
}

// ====START OF HELPER FUNCTIONS==============================================================================================

unsigned int CanCardPCan::GetFunctionAdress(HINSTANCE h_module)
{
	//Lade alle Funktionen
	if(h_module == NULL)
		return false;
	
	m_CAN_Init = (PCAN_Init) GetProcAddress(h_module, "CAN_Init");
	if (m_CAN_Init == NULL)
		return false;
	
	m_CAN_Close = (PCAN_Close) GetProcAddress(h_module, "CAN_Close");
	if(m_CAN_Close == NULL)
		return false;
	
	m_CAN_Status = (PCAN_Status) GetProcAddress(h_module, "CAN_Status");
	if(m_CAN_Status == NULL)
		return false;
	
	m_CAN_Write = (PCAN_Write) GetProcAddress(h_module, "CAN_Write");
	if(m_CAN_Write == NULL)
		return false;
	
	m_CAN_Read = (PCAN_Read) GetProcAddress(h_module, "CAN_Read");
	if(m_CAN_Read == NULL)
		return false;
	
	m_CAN_VersionInfo = (PCAN_VersionInfo) GetProcAddress(h_module, "CAN_VersionInfo");
	if(m_CAN_VersionInfo == NULL)
		return false;
	
	return true;
}


bool CanCardPCan::LoadDLL(const char* dllName)
{
	/*if(m_i_DLL != NULL)
	{
		cout << "PCAN ERROR : dll already loaded" << endl;
		return false;
	}

	m_i_DLL = LoadLibrary(dllName);
	if (m_i_DLL == NULL)
	{
		cout << "PCAN ERROR : can not load DLL \"" << dllName << "\"" << endl;
		return false;
	}

	if (!GetFunctionAdress(m_i_DLL))
	{
		cout << "PCAN ERROR : can not  load Function Adresses" << endl;
		return false;
	}*/
	return true;
}

bool CanCardPCan::UnloadDLL()
{
	if (m_i_DLL==NULL)
	{
		cout << "PCAN ERROR : trying to unload PCAN dll but it is not currently loaded" << endl;
		return false;
	}

	cout << "PCAN INFO: closing PCAN dll" << endl;
	FreeLibrary(m_i_DLL);
	m_i_DLL = NULL;

	m_CAN_Init=NULL;
	m_CAN_Close=NULL;
	m_CAN_Status=NULL;
	m_CAN_Write=NULL;
	m_CAN_Read=NULL;
	m_CAN_VersionInfo=NULL;

	return true;
}

void CanCardPCan::check_can_err(DWORD err, char* txtbuff)
{
#define CAN_ERR_HWINUSE   0x0400  // Hardware used by net
#define CAN_ERR_NETINUSE  0x0800  // net in use
#define CAN_ERR_ILLHW     0x1400  // illegal Hardware handle
#define CAN_ERR_ILLNET    0x1800  // illegal Net handle
#define CAN_ERR_ILLCLIENT 0x1C00  // illegal Client handle
	
	strcpy(txtbuff, "Error: ") ;
	if ( err == CAN_ERR_OK )        strcpy(txtbuff, "OK ") ;
	if ( err & CAN_ERR_XMTFULL )    strcat(txtbuff, "XMTFULL ") ;
	if ( err & CAN_ERR_OVERRUN )    strcat(txtbuff, "OVERRUN ") ;
	if ( err & CAN_ERR_BUSLIGHT )   strcat(txtbuff, "BUSLIGHT ") ;
	if ( err & CAN_ERR_BUSHEAVY )   strcat(txtbuff, "BUSHEAVY ") ;
	if ( err & CAN_ERR_BUSOFF )     strcat(txtbuff, "BUSOFF ") ;
	if ( err & CAN_ERR_QRCVEMPTY )  strcat(txtbuff, "QRCVEMPTY ") ;
	if ( err & CAN_ERR_QOVERRUN )   strcat(txtbuff, "QOVERRUN ") ;
	if ( err & CAN_ERR_QXMTFULL )   strcat(txtbuff, "QXMTFULL ") ;
	if ( err & CAN_ERR_REGTEST )    strcat(txtbuff, "REGTEST ") ;
	/*if ( err & CAN_ERR_NOVXD )      strcat(txtbuff, "NOVXD ") ;
	if ( (err & CAN_ERRMASK_ILLHANDLE) == CAN_ERR_HWINUSE ) strcat(txtbuff, "HWINUSE ") ;
	if ( (err & CAN_ERRMASK_ILLHANDLE) == CAN_ERR_NETINUSE ) strcat(txtbuff, "NETINUSE ") ;
	if ( (err & CAN_ERRMASK_ILLHANDLE) == CAN_ERR_ILLHW )strcat(txtbuff, "ILLHW ") ;
	if ( (err & CAN_ERRMASK_ILLHANDLE) == CAN_ERR_ILLCLIENT )strcat(txtbuff, "ILLCLIENT ") ;
	if ( (err & CAN_ERRMASK_ILLHANDLE) == CAN_ERR_ILLNET ) strcat(txtbuff, "ILLNET ") ;*/
	if ( err & CAN_ERR_RESOURCE ) strcat(txtbuff, "RESOURCE ") ;
	if ( err & CAN_ERR_ILLPARAMTYPE ) strcat(txtbuff, "ILLPARAMTYPE ") ;
	if ( err & CAN_ERR_ILLPARAMVAL ) strcat(txtbuff, "ILLPARAMVAL ") ;
	return;
}

bool CanCardPCan::sendMB(TPCANMsg* messagebox)
{
	if (m_CAN_Write==NULL)
		return false;
	DWORD ret = m_CAN_Write(messagebox);
	if (ret!=CAN_ERR_OK)
	{
		char ErrMessage[256];
		check_can_err(ret, ErrMessage);
		cout << "PCAN ERROR : CAN_Send  " << ErrMessage << endl;
		return false;
	}
	return true;

}

